package com.imvc.servlet;

import com.imvc.action.*;
import com.imvc.util.CommonUtil;
import com.imvc.util.ReflectionUtil;

import javax.print.attribute.standard.MediaSize;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * 前端控制器
 *
 * @author ml
 * @create 2017-10-18--10:12
 */
@WebServlet(urlPatterns = {"*.do"}, loadOnStartup = 0,
        initParams = {
                @WebInitParam(name = "packagePrefix", value = "com.imvc.action."),
                @WebInitParam(name = "jspPrefix", value = "/WEB-INF/jsp/"),
                @WebInitParam(name = "actionSuffix", value = "Action")
        })
public class FrontControllerServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private static final String DEFAULT_PACKAGE_NAME = "com.imvc.action.";

    private static final String DEFAULT_ACTION_NAME = "Action";

    private static final String DEFAULT_JSP_PATH = "/WEB-INF/content/";

    private String packagePrefix=null;
    private String jspPrefix=null;
    private String actionSuffix=null;

    @Override
    public void init(ServletConfig config) throws ServletException {
        String initParam=config.getInitParameter("packagePrefix");
        packagePrefix = initParam!=null?initParam:DEFAULT_PACKAGE_NAME;

        initParam=config.getInitParameter("jspPrefix");
        jspPrefix = initParam!=null?initParam:DEFAULT_JSP_PATH;

        initParam=config.getInitParameter("actionSuffix");
        actionSuffix = initParam!=null?initParam:DEFAULT_ACTION_NAME;
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String contextPath = req.getContextPath() + "/";
        //获取请求路径
        String requestPath = req.getServletPath();

        try {
            int i=1/0;
            //通过反射来创建Action对象并调用
            Action action = (Action) Class.forName(getFullActionName(requestPath)).newInstance();
            //向Action对象中注入请求参数
            injectProperties(action,req);
            //通过接口向实现类注入属性
            if(action instanceof Uploadable){

                List<Part> fileParts=new ArrayList<>();
                List<String> fileNames=new ArrayList<>();
                for(Part part:req.getParts()){
                    String cd=part.getHeader("Content-Disposition");
                    if(cd.contains("filename")){

                        fileParts.add(part);
                        fileNames.add(cd.substring(cd.lastIndexOf("=")+1).replaceAll("\\\\",""));
                    }
                }
                ((Uploadable) action).setParts(fileParts.toArray(new Part[fileParts.size()]));
                ((Uploadable) action).setFileNames(fileNames.toArray(new String[fileNames.size()]));

            }
            //执行多态的方法execute()得到ActionResult
            ActionResult result = action.execute(req, resp);
            ResultType resultType = result.getResultType();
            ResultContent resultContent = result.getResultContent();
            //根据resultType决定处理的类型
            switch (resultType) {
                //跳转
                case Forward:
                    req.getRequestDispatcher(
                            getFullJspPath(requestPath) + resultContent.getUrl()).forward(req, resp);
                    break;
                //重定向
                case Redirect:
                    resp.sendRedirect(resultContent.getUrl());
                    break;
                //ajax请求
                case Ajax:
                    PrintWriter pw = resp.getWriter();
                    pw.println(resultContent.getJson());
                    pw.close();
                    break;
                //跳转到下一个控制器
                case Chain:
                    req.getRequestDispatcher(contextPath + resultContent.getUrl()).forward(req, resp);
                    break;
                //重定向到下一个控制器
                case RedirectChain:
                    resp.sendRedirect(contextPath + resultContent.getUrl());
                default:
            }
        } catch (Exception e) {
            e.printStackTrace();
            //throw new ServletException(e);
            resp.sendRedirect("error.html");
        }

    }

    private void injectProperties(Action action, HttpServletRequest req)  {
        Enumeration<String> paramNamesEnum=req.getParameterNames();
        while (paramNamesEnum.hasMoreElements()){
            String paramName=paramNamesEnum.nextElement();
            Class<?> fieldType= ReflectionUtil.getFieldType(action,paramName.replaceAll("\\[|\\]",""));
            if(fieldType!=null){
                Object paramValue=null;
                //如果是数组
                if(fieldType.isArray()){
                    //获取数组元素类型
                    Class<?> elemType=fieldType.getComponentType();
                    String[] values=req.getParameterValues(paramName);
                    paramValue= Array.newInstance(elemType,values.length);

                    for(int i=0;i<values.length;i++){
                        Object temObj=CommonUtil.changeStringToObject(elemType,values[i]);
                        Array.set(paramValue,i,temObj);

                    }
                }else{
                    paramValue=CommonUtil.changeStringToObject(fieldType,req.getParameter(paramName));
                }
                ReflectionUtil.setValue(action,paramName.replaceAll("\\[|\\]",""),paramValue);
            }
        }

    }

    private String getFullJspPath(String requestPath) {
        return jspPrefix+getSubJspPath(requestPath);
    }

    /**
     * 获取对应的Action名称
     * @param requestPath
     * @return
     */
    private String getFullActionName(String requestPath){
        int start=requestPath.lastIndexOf("/")+1;
        int end = requestPath.lastIndexOf(".do");
        return packagePrefix+getSubPackage(requestPath)+ CommonUtil.capitalize(requestPath.substring(start,end))+actionSuffix;
    }

    private String getSubPackage(String requestPath) {
        return getSubJspPath(requestPath).replaceAll("\\/",".");

    }

    private String getSubJspPath(String requestPath) {
        int start=1;
        int end=requestPath.lastIndexOf("/");
        return end>start?requestPath.substring(start, end + 1):"";
    }




}
